package com.example.carrierapp.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.util.Synthetic;

import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RoundCornerTransform extends BitmapTransformation{
    private static final String ID = "mmzx.RoundCornerTransform";
    private static final byte[] ID_BYTES = ID.getBytes(CHARSET);
    // See #738.
    private static final List<String> MODELS_REQUIRING_BITMAP_LOCK =
            Arrays.asList(
                    // Moto X gen 2
                    "XT1085",
                    "XT1092",
                    "XT1093",
                    "XT1094",
                    "XT1095",
                    "XT1096",
                    "XT1097",
                    "XT1098"
            );
    /**
     * https://github.com/bumptech/glide/issues/738 On some devices (Moto X with android 5.1) bitmap
     * drawing is not thread safe.
     * This lock only locks for these specific devices. For other types of devices the lock is always
     * available and therefore does not impact performance
     */
    private static final Lock BITMAP_DRAWABLE_LOCK =
            MODELS_REQUIRING_BITMAP_LOCK.contains(Build.MODEL)
                    && Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1
                    ? new ReentrantLock() : new NoLock();

    private int roundingRadius;

    private static RoundCornerTransform sRoundCornerTransform;

    /**
     * 获取默认4dip圆角
     * @param context
     * @return
     */
    @MainThread
    public static RoundCornerTransform getDefault(Context context) {
        if (sRoundCornerTransform == null) {
            sRoundCornerTransform = new RoundCornerTransform(DisplayUtil.dip2px(context, 4));
        }
        return sRoundCornerTransform;
    }

    public RoundCornerTransform(int roundingRadius) {
        this.roundingRadius = roundingRadius;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap inBitmap, int outWidth, int outHeight) {
//        TransformationUtils.roundedCorners();
        Bitmap toTransform = getAlphaSafeBitmap(pool, inBitmap);
        Bitmap result = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        result.setHasAlpha(true);
        BitmapShader shader = new BitmapShader(toTransform, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(shader);
        RectF rect = new RectF(0, 0, result.getWidth(), result.getHeight());
        BITMAP_DRAWABLE_LOCK.lock();
        try {
            Canvas canvas = new Canvas(result);
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            canvas.drawRoundRect(rect, roundingRadius, roundingRadius, paint);
            canvas.setBitmap(null);
        } finally {
            BITMAP_DRAWABLE_LOCK.unlock();
        }

        if (!toTransform.equals(inBitmap)) {
            pool.put(toTransform);
        }

        return result;
    }

    @Override
    public boolean equals(Object o) {
        return (o instanceof RoundCornerTransform) && ((RoundCornerTransform) o).roundingRadius == roundingRadius;
    }

    @Override
    public int hashCode() {
        return ID.hashCode() + roundingRadius;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(ID_BYTES);

        byte[] radiusData = ByteBuffer.allocate(4).putInt(roundingRadius).array();
        messageDigest.update(radiusData);
    }

    private static Bitmap getAlphaSafeBitmap(@NonNull BitmapPool pool,
                                             @NonNull Bitmap maybeAlphaSafe) {
        if (Bitmap.Config.ARGB_8888.equals(maybeAlphaSafe.getConfig())) {
            return maybeAlphaSafe;
        }

        Bitmap argbBitmap = pool.get(maybeAlphaSafe.getWidth(), maybeAlphaSafe.getHeight(),
                Bitmap.Config.ARGB_8888);
        new Canvas(argbBitmap).drawBitmap(maybeAlphaSafe, 0 /*left*/, 0 /*top*/, null /*paint*/);

        // We now own this Bitmap. It's our responsibility to replace it in the pool outside this method
        // when we're finished with it.
        return argbBitmap;
    }

    private static final class NoLock implements Lock {

        @Synthetic
        NoLock() { }

        @Override
        public void lock() {
            // do nothing
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            // do nothing
        }

        @Override
        public boolean tryLock() {
            return true;
        }

        @Override
        public boolean tryLock(long time, @NonNull TimeUnit unit) throws InterruptedException {
            return true;
        }

        @Override
        public void unlock() {
            // do nothing
        }

        @NonNull
        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException("Should not be called");
        }
    }
}
